package j.util.jdbc.simple.core.support;

import j.util.New;
import j.util.StringUtils;
import j.util.jdbc.JdbcUtils;
import j.util.jdbc.simple.metadata.Column;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

public class SqlUtils {
	/**
	 * 当map中的数据做where，都将在key的末尾增加该词辍
	 */
	public static final String WHERE_KEY_SUFFIX = "_w";
	/**
	 * 为自定义where语句(CW)的参数生成符合simplejdbc的标准
	 * @param entityAttributeName 实体属性名称，非数据库中字段名称，不区分大小写
	 * @param operator 比较运算符，如= >= <=
	 * @param logicalOperator 逻辑连接运算符，如or and
	 * @return
	 */
	public static String toCWArgument(String entityAttributeName,
			DbOperator operator,DbOperator logicalOperator){
		String ret = entityAttributeName;
		if(null!=operator){
			ret+="$"+operator.toString();
			if(null!=logicalOperator){
				ret += "$"+logicalOperator;
			}
		}else{
			if(null!=logicalOperator){
				ret += "$$"+logicalOperator;
			}
		}
		return ret;
	}
	/**
	 * 从复合主键中生成sql中的where语句部分，并会自动加上扩号
	 * @param pkColumn
	 * @param argsOrder
	 * @return
	 */
	public static String fromCompositeColumnsToWhereSql(String pkColumn,List<String> argsOrder){
		StringBuilder sb = new StringBuilder();
		String[] sa = pkColumn.split(",");
		String s;
		if(sa.length>1){
			sb.append("(");
			for(int j = 0;j<sa.length;j++){
				if(j>0){
					sb.append(DbOperator.LogicalAND);
				}
				s = sa[j];
				sb.append(s).append(DbOperator.EQ).append("?");
				argsOrder.add(s);
			}
			sb.append(")");
		}else{
			s = sa[0];
			sb.append(s).append(DbOperator.EQ).append("?");
			argsOrder.add(s);
		}
		return sb.toString();
	}
	/**
	 * 通用方法，将字段列表生成操作前的检查代码，字段与字段之间以or连接，但复合字段之间用and连接
	 * 字段的名字必须以数据库中的字段名字
	 * @param columns
	 * @param order
	 * @return
	 */
	public static String fromColumnsToWhereSqlForDMLCheck(List<String> columns,List<String> order){
		if(null==columns || columns.size()==0){
			return "";
		}
		StringBuilder sb = new StringBuilder();
		String s = null;
		String[] sa = null;
		for(int i=0;i<columns.size();i++){
			if(i>0){
				sb.append(DbOperator.LogicalOR);
			}
			s = columns.get(i);
			//检查是否为复合主键(如两个字段或更多为主键)，若是，则构造出类似(pk1=? and pk2=?)
			sa = s.split(",");
			if(sa.length>1){
				sb.append("(");
				for(int j = 0;j<sa.length;j++){
					if(j>0){
						sb.append(DbOperator.LogicalAND);
					}
					s = sa[j];
					sb.append(s).append(DbOperator.EQ).append("?");
					order.add(s);
				}
				sb.append(")");
			}else{
				s = sa[0];
				sb.append(s).append(DbOperator.EQ).append("?");
				order.add(s);
			}
		}
		return sb.toString();
	}
	/**
	 * 根据指定的列生成where语句，之间以逗号隔开
	 * @param columns
	 * @param order
	 * @return
	 */
	public static String fromColumnsToWhereSql(List<String> columns,List<String> order){
		if(null==columns || columns.size()==0){
			return "";
		}
		StringBuilder sb = new StringBuilder();
		String s;
		for(int i=0;i<columns.size();i++){
			if(i>0){
				sb.append(DbOperator.LogicalOR);
			}
			s = columns.get(i);
			sb.append(s).append(DbOperator.EQ).append("?");
			order.add(s);
		}
		return sb.toString();
	}
	/**
	 * 根据用户自指定的参数形成where部分，该map建议为有序，当然也可是无序的，若是无序的，且在key中指定了与下个字段的逻辑运算符，则最终的结果可能不是预期的
	 * 同时将args参数集的key转换为以数据库字段为key的map
	 * map中key的完整示例如下：id$>$and$一元函数
	 * @param entityAttributeColumnMap 实体属性与数据库字段名字的映射
	 * @param args
	 * @param order
	 * @return
	 */
	public static String fromArgsToWhereSql(Map<String,String> entityAttributeColumnMap,
			Map<String,Object> args,List<String> order){
		if(null==args || args.size()==0){
			return null;
		}
		StringBuilder sql = new StringBuilder();
		//定义下一个字段逻辑运算符为AND
		int i = 0;
		String[] keyArr;
		String nextLogical = DbOperator.LogicalAND.toString();
		String opt = DbOperator.EQ.toString();
		String dbColumn,funtionName=null;
		//以数据库字段名字为key的参数集
		Map<String,Object> dbColumnKeyMap = New.map();
		for(Map.Entry<String, Object> entry : args.entrySet()){
			keyArr = entry.getKey().split("\\$");
			dbColumn = entityAttributeColumnMap.get(keyArr[0].toUpperCase());
			if(StringUtils.isNullOrEmpty(dbColumn)){
				//用户指定的实体属性不存在
				continue;
			}
			if(i++>0){
				sql.append(" ").append(nextLogical).append(" ");
				//将操作及逻辑运算符回归为默认值
				nextLogical = DbOperator.LogicalAND.toString();
				opt = DbOperator.EQ.toString();
				funtionName = null;
			}
			//取出运算符，为key中的第二段
			if(keyArr.length>1){
				if(StringUtils.isNotEmpty(keyArr[1])){
					opt = keyArr[1];
				}
				//取出逻辑运算符，为key中的第三段
				if(keyArr.length == 3){
					if(StringUtils.isNotEmpty(keyArr[2])){
						nextLogical = keyArr[2];
					}
				}
				//取出该字段上是否使用了函数计算，函数只能用一元函数，若有多元函数时，请不要使用simplejdbc
				if(keyArr.length == 4){
					funtionName = keyArr[3];
				}
			}
			if(StringUtils.isNotEmpty(funtionName)){
				//该字段上有一元函数
				sql.append(funtionName).append("(").append(dbColumn).append(")");
			}else{
				sql.append(dbColumn);
			}
			dbColumn += SqlUtils.WHERE_KEY_SUFFIX;
			sql.append(opt).append("?");
			order.add(dbColumn);
			dbColumnKeyMap.put(dbColumn, args.get(entry.getKey()));
		}
		//将原来的项清除掉
		args.clear();
		//再将以数据库字段为名字的项加入之中
		args.putAll(dbColumnKeyMap);
		return sql.toString();
	}
	/**
	 * 构造sql查询语句中order by部分
	 * @param entityAttributeColumnMap
	 * @param orders
	 * @return
	 */
	public static String fromMapToOrderby(
			Map<String, String> entityAttributeColumnMap,
			Map<String, String> orders) {
		if(null==orders || orders.size() == 0){
			return null;
		}
		StringBuilder orderby = new StringBuilder();
		String dbColumn;
		int i = 0;
		for(Map.Entry<String, String> entry : orders.entrySet()){
			dbColumn= entityAttributeColumnMap.get(entry.getKey().toUpperCase());
			if(StringUtils.isNotEmpty(dbColumn)){
				if(i++>0){
					orderby.append(",");
				}
				orderby.append(dbColumn);
				if(StringUtils.isNullOrEmpty(entry.getValue())){
					orderby.append(" ASC");
				}else{
					orderby.append(" ").append(entry.getValue().toUpperCase());
				}
			}
		}
		return orderby.toString();
	}    /**
     * 执行一个sql语句，并将结果生成一个map，map的key为数据库中的字段名
     * @param conn
     * @param sql
     * @param args
     * @param argsOrder
     * @return
     */
    public static Map<String,Object> queryForMap(Map<String,Column> metaData,Connection conn,String sql,Map<String,Object> args,List<String> argsOrder){
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try{
            stmt = conn.prepareStatement(sql);
            SimpleJdbcUtils.setPreapredStatementParameters(metaData, stmt, argsOrder, args);
            rs = stmt.executeQuery();
            if(rs.next())
                return SimpleJdbcUtils.fromResultSetToMap(rs);
        }catch(Exception ex){
            ex.printStackTrace();
        }finally{
            JdbcUtils.free(null, stmt, rs);
        }
        return null;
    }
}
